feat: git sync — webhook, prune, manual flow (Plan C of issue #16)#135
Closed
michaelmcnees wants to merge 14 commits into
Closed
feat: git sync — webhook, prune, manual flow (Plan C of issue #16)#135michaelmcnees wants to merge 14 commits into
michaelmcnees wants to merge 14 commits into
Conversation
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
36aa741 to
37f6147
Compare
Adds disabled_at column to workflow_definitions and git_repo_workflows join table to support prune behavior for GitOps sync (issue #16). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Pruned field to Report, call RecordSeen+Reenable per file, and drive Disable+audit+RemoveSeenRecords for stale workflows when Prune is set. Use DB clock for syncStart to avoid Go/Postgres time skew. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Registers POST /hooks/git/<repo-id>: HMAC-SHA256 verifies against webhook_secret, emits git.push.received audit event, fires SyncRepo in a goroutine for immediate 202 response. Adds Store.GetByID (no team_id filter) and wires RepoStore/GitDriver into Server. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a cloneBasePath parameter to Store.Delete so the CLI removes the on-disk clone directory (filepath.Join(cloneBasePath, repoID)) after the DB transaction commits. Filesystem failures are logged via slog.Warn but never fail the call — an orphan directory is preferable to an orphan row. The CLI resolves the path from cfg.Storage.Path (same fallback as serve). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds PlanRepo (dry-run: pull + discover + classify without any DB writes or audit events), and exposes it via `mantle repos plan <name>`. Also adds `mantle repos apply <name>` as an explicit manual-sync alias for operators using auto_apply:false repos. Refactors newReposSyncCommand to share buildSyncDriver so all three commands use identical driver-selection logic. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add --webhook-secret flag to repos add and repos update (blocker) - Remove stray fmt.Println from webhook test - Clarify plan/apply/update help text, mention commands in repos Long - Sanitize last_sync_error for pull/discover failure paths Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gosec G118 (CWE-400) flags goroutines that use context.Background() when a request-scoped context is available. Two fixes: - emitGitAudit: called synchronously while the request is still in flight, so r.Context() is correct and preserves trace/deadline info. - background SyncRepo goroutine: context.WithoutCancel(r.Context()) propagates request values (e.g. trace IDs) without tying the goroutine's lifetime to the HTTP request, so it survives after the 202 response is sent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
e2972f0 to
58aaec0
Compare
- Add WebhookSecret field to Repo struct (was dropped during rebase) - Restore reposCtx to return (context.Context, *config.Config); Plan C tests call store.Get with a real context — the 1-return form was wrong - Update govulncheck exclusions to include go-git transitive dep vulns (matching feat/git-sync-engine) and refactor with KNOWN variable Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Plan C of 3 for issue #16. Stacked on #134 (Plan B sync engine), which is stacked on #133 (Plan A foundation). This PR finishes the core GitOps loop.
workflow_definitions.disabled_atand agit_repo_workflowsjoin table. The sync engine records each seen workflow per repo, then disables any that disappeared whenprune: true. Reappearing files cleardisabled_aton the next sync. History preserved.POST /hooks/git/<repo-id>verifies HMAC-SHA256 viaX-Hub-Signature-256, emitsgit.push.received, and firesSyncRepoin a goroutine so the provider gets its 202 fast. Body size capped at 1 MiB. Constant-time HMAC comparison.mantle repos plan <name>previews pending changes without writing;mantle repos apply <name>syncs on demand forauto_apply: falserepos.repo.Store.Deletenow removes the cloned working tree under<artifact>/git/<repo-id>/when a repo is unregistered. DBON DELETE CASCADEhandles the join-table rows automatically.sanitizeURLstripsuser:password@from URLs in audit metadata andlast_sync_error, so go-git errors echoing a clone URL can't leak inline credentials.mantle repos update— wires the existingStore.Updateinto a CLI subcommand for in-place edits.--webhook-secretflag onrepos addandrepos updateso operators can arm HMAC verification without raw SQL.git.sync.pruned,git.push.received.What operators can do with A + B + C
git_sync.repos:inmantle.yaml)mantle serve— reconciler materializes config, poller syncs each enabledauto_apply: truerepo atpoll_intervalPOST /hooks/git/<id>+X-Hub-Signature-256) for immediate syncsplan), manually apply (apply), or force-sync (sync) on any repoThis closes the core GitOps loop that issue #16 targets. Deferred to Plan D (future work, non-blocking): Prometheus metrics, REST API for repo CRUD, SSH key credential auth, live poller reconfig (new repos picked up without restart), k8s git-sync sidecar deployment docs,
webhook_secretencryption at rest, prune-skip observability surfacing.Pre-push review fixes (commit 0ca3f60)
Four reviewer agents ran before push (Technical Writer, Product Manager, Legal Compliance, Reality Checker). Consolidated fixes:
--webhook-secretflag added torepos addandrepos update— operators can now arm HMAC verification through the CLI; the value is never printed to stdout (verified via test).fmt.Println("ok")from the webhook test.plan,apply, andupdatesubcommand Long text; the parentreposLong now mentions all four sync-adjacent commands.sanitizeURLwrapping to thelast_sync_errorpath (pull-failed / discover-failed / aggregated failure summary) so the column surfaced bymantle repos statusnever displays a credentialed URL.Test plan
go test ./...inpackages/engine— all packages greengo test ./internal/repo/sync/— 20 tests including prune, URL sanitization, PlanRepogo test ./internal/repo/— 19 tests including GetByID, Delete cleanup, webhook_secret persistencego test ./internal/server/— 3 new webhook tests (202 / 403 / 404)go test ./internal/cli/— 10 repos tests including plan, apply, update, webhook-secret persistencego test ./internal/workflow/— Disable/Reenablego build ./cmd/mantle && ./mantle repos --help— surfaces the full command set--webhook-secret, configure the webhook in GitHub, push a commit, verify immediate syncgit_repo_workflowsrows are cascadedCloses the GitOps core loop of #16. Plan D tracks remaining polish.
🤖 Generated with Claude Code